import { defineComponent, onMounted, PropType, ref, VNode } from 'vue';
import { IPanelButton } from '@ibiz/model-core';
import { showTitle } from '@ibiz-template/core';
import { useNamespace } from '@ibiz-template/vue3-util';
import { AIAssistantButtonController } from './ai-assistant-button.controller';
import { isWithinBounds, limitDraggable } from './drag-util';
import './ai-assistant-button.scss';

const AISvg = (): VNode => (
  <svg viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg'>
    <path d='M481.0752 263.3728l50.9952 1.024 1.8432-105.8816-50.9952-0.8192z'></path>
    <path d='M486.441426 180.895362a66.56 66.56 0 1 0 42.091944-126.290153 66.56 66.56 0 1 0-42.091944 126.290153Z'></path>
    <path d='M138.8544 664.3712c-52.8384 0-95.8464-43.008-95.8464-95.8464s43.008-95.8464 95.8464-95.8464M880.0256 472.6784c52.8384 0 95.8464 43.008 95.8464 95.8464s-43.008 95.8464-95.8464 95.8464'></path>
    <path d='M507.4944 220.5696c-220.16 0-398.7456 162.816-398.7456 363.7248s178.5856 363.7248 398.7456 363.7248 398.7456-162.816 398.7456-363.7248-178.5856-363.7248-398.7456-363.7248z m0 559.9232c-166.2976 0-301.2608-100.5568-301.2608-224.4608s134.9632-224.4608 301.2608-224.4608S808.7552 432.128 808.7552 556.032 673.792 780.4928 507.4944 780.4928z'></path>
    <path d='M319.6928 556.032a47.9232 38.912 90 1 0 77.824 0 47.9232 38.912 90 1 0-77.824 0Z'></path>
    <path d='M617.472 556.032a47.9232 38.912 90 1 0 77.824 0 47.9232 38.912 90 1 0-77.824 0Z'></path>
  </svg>
);

/**
 * AI面板按钮
 * @primary
 * @description 面板中最常见的按钮组件，支持配置界面行为、界面逻辑等，同时支持权限配置是否显示、是否禁用。
 */
export const AIAssistantButton = defineComponent({
  name: 'IBizAIAssistantButton',
  props: {
    /**
     * @description 面板项模型数据
     */
    modelData: { type: Object as PropType<IPanelButton>, required: true },
    /**
     * @description 面板项控制器
     */
    controller: {
      type: AIAssistantButtonController,
      required: true,
    },
  },
  setup(props) {
    const ns = useNamespace('ai-assistant-button');

    const { sysImage, buttonCssStyle, tooltip = 'AI助手' } = props.modelData;

    const { state } = props.controller;

    const tempStyle = ref('');

    if (buttonCssStyle) {
      tempStyle.value = buttonCssStyle;
    }

    const POSITION_CHCHE = 'ai-assistant-button-position-style';
    const btnRef = ref();
    const position = ref();
    const positionStyle = ref();
    const isDragging = ref(false);
    const adsorption = ref('');

    /**
     * 计算吸附
     */
    const calcAdsorption = (): void => {
      if (!position.value) return;
      // 计算吸附
      const elementWidth = btnRef.value.offsetWidth || 56;
      const windowWidth = window.innerWidth;
      // 吸附触发距离（px）
      const adsorptionNum = 20;

      const elementRight = position.value.x * windowWidth + elementWidth;
      const distanceToRight = windowWidth - elementRight;
      if (position.value.x * windowWidth <= adsorptionNum) {
        adsorption.value = 'adsorption-left';
      } else if (distanceToRight <= adsorptionNum) {
        adsorption.value = 'adsorption-right';
      }
    };

    /**
     * 设置样式
     */
    const setStyle = (): void => {
      if (!position.value) return;
      positionStyle.value = {
        [ns.cssVarBlockName('position-drag-left')]:
          `${position.value.x * 100}%`,
        [ns.cssVarBlockName('position-drag-top')]: `${position.value.y * 100}%`,
      };
      localStorage.setItem(POSITION_CHCHE, JSON.stringify(position.value));
    };

    /**
     * 注册最小化拖拽
     *
     * @returns
     */
    const registerDragMinmize = (): void => {
      const container = btnRef.value;
      if (!container) return;
      container.onmousedown = (e: MouseEvent): void => {
        // 禁止选择文本，避免拖动时出现选择效果
        document.body.style.userSelect = 'none';
        const offsetX = e.clientX - container.offsetLeft;
        const offsetY = e.clientY - container.offsetTop;
        const start = Date.now();
        const onMouseMove = (evt: MouseEvent): void => {
          // 开始拖动前清空吸附
          if (adsorption.value) adsorption.value = '';
          const width = 56 / window.innerWidth;
          const height = 56 / window.innerHeight;
          const { x, y } = limitDraggable(
            evt.clientX - offsetX,
            evt.clientY - offsetY,
            width,
            height,
          );
          position.value = { x, y };
          requestAnimationFrame(() => {
            setStyle();
          });
        };
        const onMouseUp = (): void => {
          // 恢复选择文本功能
          const end = Date.now();
          // 鼠标按下到抬起的时间超过300毫秒则认定为拖拽中
          isDragging.value = end - start > 300;
          calcAdsorption();
          document.body.style.userSelect = '';
          document.removeEventListener('mousemove', onMouseMove);
          document.removeEventListener('mouseup', onMouseUp);
        };

        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseup', onMouseUp);
      };
    };

    const handleButtonClick = async (event: MouseEvent): Promise<void> => {
      if (isDragging.value) return;
      await props.controller.onActionClick(event);
      props.controller.onClick(event);
    };

    onMounted(() => {
      const cache = localStorage.getItem(POSITION_CHCHE);
      if (cache) {
        const data = JSON.parse(cache);
        position.value = {};
        if (isWithinBounds(data)) Object.assign(position.value, data);
      }
      setStyle();
      registerDragMinmize();
      calcAdsorption();
    });

    return {
      ns,
      btnRef,
      state,
      sysImage,
      tooltip,
      tempStyle,
      adsorption,
      positionStyle,
      handleButtonClick,
    };
  },
  render() {
    if (this.state.visible) {
      const align = this.controller.customizedAlign.toLocaleLowerCase();
      return (
        <div
          ref='btnRef'
          class={[
            this.ns.b(),
            this.ns.is(align, !!align),
            this.ns.is('drag', !!this.positionStyle),
            this.ns.is(this.adsorption, !!this.adsorption),
            this.tempStyle,
            ...this.controller.containerClass,
          ]}
          style={this.positionStyle}
          title={showTitle(this.tooltip)}
          onClick={this.handleButtonClick}
        >
          <div class={this.ns.e('content')}>
            {this.sysImage ? (
              <iBizIcon
                class={this.ns.em('content', 'icon')}
                icon={this.sysImage}
              />
            ) : (
              AISvg()
            )}
          </div>
        </div>
      );
    }
    return null;
  },
});
export default AIAssistantButton;
